package core;

import java.lang.reflect.Array;
import java.util.*;

/**
 * 数组工具类
 * <p>
 * 提供数组相关的操作，包括数组判空、数组转换、数组比较等方法。
 * </p>
 */
public class ArrayUtil {
    // 优化索引计算逻辑
    private static int calculateIndex(int index, int length) {
        if (index < 0) {
            index += length;
        }
        return (index < 0 || index >= length) ? -1 : index;
    }

    // region ----- isEmpty

    /**
     * 数组是否为空
     *
     * @param <T>   数组元素类型
     * @param array 数组
     * @return 是否为空
     */
    public static <T> boolean isEmpty(T[] array) {
        return array == null || array.length == 0;
    }

    /**
     * 数组是否为空
     *
     * @param array 数组
     * @return 是否为空
     */
    public static boolean isEmpty(int[] array) {
        return array == null || array.length == 0;
    }

    /**
     * 数组是否为空
     *
     * @param array 数组
     * @return 是否为空
     */
    public static boolean isEmpty(long[] array) {
        return array == null || array.length == 0;
    }

    /**
     * 数组是否为空
     *
     * @param array 数组
     * @return 是否为空
     */
    public static boolean isEmpty(double[] array) {
        return array == null || array.length == 0;
    }

    /**
     * 数组是否为空
     *
     * @param array 数组
     * @return 是否为空
     */
    public static boolean isEmpty(float[] array) {
        return array == null || array.length == 0;
    }

    /**
     * 数组是否为空
     *
     * @param array 数组
     * @return 是否为空
     */
    public static boolean isEmpty(boolean[] array) {
        return array == null || array.length == 0;
    }

    /**
     * 数组是否为空
     *
     * @param array 数组
     * @return 是否为空
     */
    public static boolean isEmpty(byte[] array) {
        return array == null || array.length == 0;
    }

    /**
     * 数组是否为空
     *
     * @param array 数组
     * @return 是否为空
     */
    public static boolean isEmpty(char[] array) {
        return array == null || array.length == 0;
    }

    /**
     * 数组是否为空
     *
     * @param array 数组
     * @return 是否为空
     */
    public static boolean isEmpty(short[] array) {
        return array == null || array.length == 0;
    }

    // endregion

    // region ----- isNotEmpty

    /**
     * 数组是否为非空
     *
     * @param <T>   数组元素类型
     * @param array 数组
     * @return 是否为非空
     */
    public static <T> boolean isNotEmpty(T[] array) {
        return !isEmpty(array);
    }

    /**
     * 数组是否为非空
     *
     * @param array 数组
     * @return 是否为非空
     */
    public static boolean isNotEmpty(int[] array) {
        return !isEmpty(array);
    }

    /**
     * 数组是否为非空
     *
     * @param array 数组
     * @return 是否为非空
     */
    public static boolean isNotEmpty(long[] array) {
        return !isEmpty(array);
    }

    /**
     * 数组是否为非空
     *
     * @param array 数组
     * @return 是否为非空
     */
    public static boolean isNotEmpty(double[] array) {
        return !isEmpty(array);
    }

    /**
     * 数组是否为非空
     *
     * @param array 数组
     * @return 是否为非空
     */
    public static boolean isNotEmpty(float[] array) {
        return !isEmpty(array);
    }

    /**
     * 数组是否为非空
     *
     * @param array 数组
     * @return 是否为非空
     */
    public static boolean isNotEmpty(boolean[] array) {
        return !isEmpty(array);
    }

    /**
     * 数组是否为非空
     *
     * @param array 数组
     * @return 是否为非空
     */
    public static boolean isNotEmpty(byte[] array) {
        return !isEmpty(array);
    }

    /**
     * 数组是否为非空
     *
     * @param array 数组
     * @return 是否为非空
     */
    public static boolean isNotEmpty(char[] array) {
        return !isEmpty(array);
    }

    /**
     * 数组是否为非空
     *
     * @param array 数组
     * @return 是否为非空
     */
    public static boolean isNotEmpty(short[] array) {
        return !isEmpty(array);
    }

    // endregion

    // region ----- get length

    /**
     * 获取数组长度
     * <p>
     * 如果数组为null，返回0
     * </p>
     *
     * @param array 数组
     * @return 数组长度
     */
    public static int length(Object array) {
        if (array == null) {
            return 0;
        }
        return Array.getLength(array);
    }

    // endregion

    // region ----- get

    /**
     * 获取数组对象中指定index的值，支持负数，例如-1表示倒数第一个值
     *
     * @param <T>   数组元素类型
     * @param array 数组对象
     * @param index 下标，支持负数
     * @return 值
     */
    public static <T> T get(T[] array, int index) {
        if (isEmpty(array)) return null;
        int calculatedIndex = calculateIndex(index, array.length);
        return calculatedIndex == -1 ? null : array[calculatedIndex];
    }

    /**
     * 获取数组对象中指定index的值，支持负数，例如-1表示倒数第一个值
     *
     * @param array 数组对象
     * @param index 下标，支持负数
     * @return 值
     */
    public static int get(int[] array, int index) {
        if (isEmpty(array)) {
            return 0;
        }
        if (index < 0) {
            index += array.length;
        }
        if (index < 0 || index >= array.length) {
            return 0;
        }
        return array[index];
    }

    /**
     * 获取数组对象中指定index的值，支持负数，例如-1表示倒数第一个值
     *
     * @param array 数组对象
     * @param index 下标，支持负数
     * @return 值
     */
    public static long get(long[] array, int index) {
        if (isEmpty(array)) {
            return 0L;
        }
        if (index < 0) {
            index += array.length;
        }
        if (index < 0 || index >= array.length) {
            return 0L;
        }
        return array[index];
    }

    // endregion

    // region ----- join

    /**
     * 以 conjunction 为分隔符将数组转换为字符串
     *
     * @param <T>         数组元素类型
     * @param array       数组
     * @param conjunction 分隔符
     * @return 连接后的字符串
     */
    public static <T> String join(T[] array, CharSequence conjunction) {
        return join(array, conjunction, null, null);
    }

    /**
     * 以 conjunction 为分隔符将数组转换为字符串
     *
     * @param <T>         数组元素类型
     * @param array       数组
     * @param conjunction 分隔符
     * @param prefix      每个元素前缀
     * @param suffix      每个元素后缀
     * @return 连接后的字符串
     */
    public static <T> String join(T[] array, CharSequence conjunction, String prefix, String suffix) {
        if (isEmpty(array)) {
            return "";
        }

        final StringBuilder sb = new StringBuilder();
        boolean isFirst = true;
        for (T item : array) {
            if (isFirst) {
                isFirst = false;
            } else {
                sb.append(conjunction);
            }
            if (ObjectUtil.isNotEmpty(prefix)) {
                sb.append(prefix);
            }
            if (null != item) {
                sb.append(item);
            }
            if (ObjectUtil.isNotEmpty(suffix)) {
                sb.append(suffix);
            }
        }
        return sb.toString();
    }

    // endregion

    // region ----- remove

    /**
     * 移除数组中指定index的元素，返回剩余元素组成的新数组
     *
     * @param <T>   数组元素类型
     * @param array 数组
     * @param index 位置
     * @return 剩余元素组成的新数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] remove(T[] array, int index) {
        if (isEmpty(array)) {
            return array;
        }
        if (index < 0 || index >= array.length) {
            return array;
        }

        final Class<?> componentType = array.getClass().getComponentType();
        final T[] result = (T[]) Array.newInstance(componentType, array.length - 1);
        System.arraycopy(array, 0, result, 0, index);
        System.arraycopy(array, index + 1, result, index, array.length - index - 1);
        return result;
    }

    // endregion

    // region ----- distinct

    /**
     * 去重数组中的元素，保持元素顺序不变
     *
     * @param <T>   数组元素类型
     * @param array 数组
     * @return 去重后的数组
     */
    public static <T> T[] distinct(T[] array) {
        if (isEmpty(array)) {
            return array;
        }

        final Set<T> set = new LinkedHashSet<>(Arrays.asList(array));
        @SuppressWarnings("unchecked") final T[] result = (T[]) Array.newInstance(array.getClass().getComponentType(), set.size());
        return set.toArray(result);
    }

    // endregion

    // region ----- contains

    /**
     * 判断数组是否包含指定元素
     *
     * @param <T>   数组元素类型
     * @param array 数组
     * @param value 被检查的元素
     * @return 是否包含
     */
    public static <T> boolean contains(T[] array, T value) {
        if (isEmpty(array)) {
            return false;
        }
        for (T t : array) {
            if (ObjectUtil.equal(t, value)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断数组是否包含指定元素
     *
     * @param array 数组
     * @param value 被检查的元素
     * @return 是否包含
     */
    public static boolean contains(int[] array, int value) {
        if (isEmpty(array)) {
            return false;
        }
        for (int t : array) {
            if (t == value) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断数组是否包含指定元素
     *
     * @param array 数组
     * @param value 被检查的元素
     * @return 是否包含
     */
    public static boolean contains(long[] array, long value) {
        if (isEmpty(array)) {
            return false;
        }
        for (long t : array) {
            if (t == value) {
                return true;
            }
        }
        return false;
    }

    // endregion

    // region ----- toList

    /**
     * 数组转List
     *
     * @param <T>   元素类型
     * @param array 数组
     * @return List
     */
    public static <T> List<T> toList(T[] array) {
        if (isEmpty(array)) {
            return new ArrayList<>();
        }
        return Arrays.asList(array);
    }

    // endregion

    // region ----- reverse

    /**
     * 反转数组，会变更原数组
     *
     * @param <T>   数组元素类型
     * @param array 数组
     */
    public static <T> void reverse(T[] array) {
        if (isEmpty(array)) {
            return;
        }
        int i = 0;
        int j = array.length - 1;
        T tmp;
        while (j > i) {
            tmp = array[j];
            array[j] = array[i];
            array[i] = tmp;
            j--;
            i++;
        }
    }

    /**
     * 反转数组，会变更原数组
     *
     * @param array 数组
     */
    public static void reverse(int[] array) {
        if (isEmpty(array)) {
            return;
        }
        int i = 0;
        int j = array.length - 1;
        int tmp;
        while (j > i) {
            tmp = array[j];
            array[j] = array[i];
            array[i] = tmp;
            j--;
            i++;
        }
    }

    // endregion
}